package preprocessing;

/**
 * 完整的Porter Stemmer实现，包含全面的数组边界检查
 * 源自Martin Porter的原始算法，适用于英语词干提取
 */
public class Stemmer {
    private char[] b;       // 字符缓冲区
    private int k;          // 当前词干末尾索引
    private int k0;         // 词干起始索引
    private int j;          // 通用偏移量
    /**
     * 主方法：对单词进行词干提取
     * @param word 要处理的单词
     * @return 词干提取后的结果
     */
    public String stem(String word) {
        if (word == null || word.length() <= 1)  return word;// 空值检查和短单词处理
        b = word.toLowerCase().toCharArray(); k = b.length - 1; k0 = 0;// 初始化字符数组
        try {// 执行词干提取步骤
            step1ab();//步骤1ab：处理复数、-ed和-ing结尾
            step1c();//步骤1c：将词尾的y改为i（当词干中有元音时）
            step2();//步骤2：处理双后缀词
            step3();//步骤3：处理特定后缀
            step4();//步骤4：移除更多后缀
            step5();//步骤5：处理最后的-e和-ll
        } catch (ArrayIndexOutOfBoundsException e) {
            // 发生越界时返回原始单词（小写形式）
            return new String(b).toLowerCase();
        }
        return new String(b, 0, k + 1);
    }

    /* 步骤1ab：处理复数、-ed和-ing结尾 */
    private void step1ab() {
        if (k < k0) return;

        // 处理'ss'结尾
        if (safeEnds("sses")) {
            k -= 2;
        } else if (safeEnds("ies")) {
            safeSetTo("i");
        } else if (safeCharAt(k) == 's' && k > k0 && safeCharAt(k - 1) != 's') {
            k--;
        }

        // 处理-eed/-ed/-ing
        if (safeEnds("eed")) {
            if (m() > 0) k--;
        } else if ((safeEnds("ed") || safeEnds("ing")) && vowelInStem()) {
            k = j;
            if (safeEnds("at")) {
                safeSetTo("ate");
            } else if (safeEnds("bl")) {
                safeSetTo("ble");
            } else if (safeEnds("iz")) {
                safeSetTo("ize");
            } else if (doubleConsonant(k)) {
                k--;
                char ch = safeCharAt(k);
                if (ch == 'l' || ch == 's' || ch == 'z') {
                    k++;
                }
            } else if (m() == 1 && cvc(k)) {
                safeSetTo("e");
            }
        }
    }

    /* 步骤1c：将词尾的y改为i（当词干中有元音时） */
    private void step1c() {
        if (safeEnds("y") && vowelInStem() && k > k0) {
            b[k] = 'i';
        }
    }

    /* 步骤2：处理双后缀词 */
    private void step2() {
        if (k < k0 + 1) return;

        switch (safeCharAt(k - 1)) {
            case 'a':
                if (safeEnds("ational")) { r("ate"); break; }
                if (safeEnds("tional")) { r("tion"); break; }
                break;
            case 'c':
                if (safeEnds("enci")) { r("ence"); break; }
                if (safeEnds("anci")) { r("ance"); break; }
                break;
            case 'e':
                if (safeEnds("izer")) { r("ize"); break; }
                break;
            case 'l':
                if (safeEnds("bli")) { r("ble"); break; }
                if (safeEnds("alli")) { r("al"); break; }
                if (safeEnds("entli")) { r("ent"); break; }
                if (safeEnds("eli")) { r("e"); break; }
                if (safeEnds("ousli")) { r("ous"); break; }
                break;
            case 'o':
                if (safeEnds("ization")) { r("ize"); break; }
                if (safeEnds("ation")) { r("ate"); break; }
                if (safeEnds("ator")) { r("ate"); break; }
                break;
            case 's':
                if (safeEnds("alism")) { r("al"); break; }
                if (safeEnds("iveness")) { r("ive"); break; }
                if (safeEnds("fulness")) { r("ful"); break; }
                if (safeEnds("ousness")) { r("ous"); break; }
                break;
            case 't':
                if (safeEnds("aliti")) { r("al"); break; }
                if (safeEnds("iviti")) { r("ive"); break; }
                if (safeEnds("biliti")) { r("ble"); break; }
                break;
            case 'g':
                if (safeEnds("logi")) { r("log"); break; }
                break;
        }
    }

    /* 步骤3：处理特定后缀 */
    private void step3() {
        if (k < k0) return;

        switch (safeCharAt(k)) {
            case 'e':
                if (safeEnds("icate")) { r("ic"); break; }
                if (safeEnds("ative")) { r(""); break; }
                if (safeEnds("alize")) { r("al"); break; }
                break;
            case 'i':
                if (safeEnds("iciti")) { r("ic"); break; }
                break;
            case 'l':
                if (safeEnds("ical")) { r("ic"); break; }
                if (safeEnds("ful")) { r(""); break; }
                break;
            case 's':
                if (safeEnds("ness")) { r(""); break; }
                break;
        }
    }

    /* 步骤4：移除更多后缀 */
    private void step4() {
        if (k < k0 + 1) return;

        switch (safeCharAt(k - 1)) {
            case 'a':
                if (!safeEnds("al")) return; break;
            case 'c':
                if (!safeEnds("ance") && !safeEnds("ence")) return; break;
            case 'e':
                if (!safeEnds("er")) return; break;
            case 'i':
                if (!safeEnds("ic")) return; break;
            case 'l':
                if (!safeEnds("able") && !safeEnds("ible")) return; break;
            case 'n':
                if (!safeEnds("ant") && !safeEnds("ement") &&
                        !safeEnds("ment") && !safeEnds("ent")) return; break;
            case 'o':
                if (safeEnds("ion") && (safeCharAt(j) == 's' || safeCharAt(j) == 't')) break;
                if (!safeEnds("ou")) return; break;
            case 's':
                if (!safeEnds("ism")) return; break;
            case 't':
                if (!safeEnds("ate") && !safeEnds("iti")) return; break;
            case 'u':
                if (!safeEnds("ous")) return; break;
            case 'v':
                if (!safeEnds("ive")) return; break;
            case 'z':
                if (!safeEnds("ize")) return; break;
            default:
                return;
        }
        if (m() > 1) k = j;
    }

    /* 步骤5：处理最后的-e和-ll */
    private void step5() {
        j = k;

        if (safeCharAt(k) == 'e') {
            int a = m();
            if (a > 1 || (a == 1 && !cvc(k - 1))) {
                k--;
            }
        }
        if (safeCharAt(k) == 'l' && doubleConsonant(k) && m() > 1) {
            k--;
        }
    }

    /* ============== 辅助方法（带边界检查） ============== */

    /**
     * 安全访问字符数组
     */
    private char safeCharAt(int i) {
        if (i < 0 || i >= b.length) return 0;
        return b[i];
    }

    /**
     * 检查是否以指定字符串结尾（带边界检查）
     */
    private boolean safeEnds(String s) {
        int l = s.length();
        int o = k - l + 1;

        if (o < k0 || l > k - k0 + 1) {
            return false;
        }

        for (int i = 0; i < l; i++) {
            if (safeCharAt(o + i) != s.charAt(i)) {
                return false;
            }
        }
        j = k - l;
        return true;
    }

    /**
     * 安全设置词尾（带边界检查）
     */
    private void safeSetTo(String s) {
        int l = s.length();
        int o = j + 1;

        // 确保数组足够大
        if (o + l >= b.length) {
            char[] newb = new char[o + l + 1];
            System.arraycopy(b, 0, newb, 0, b.length);
            b = newb;
        }

        for (int i = 0; i < l; i++) {
            b[o + i] = s.charAt(i);
        }
        k = j + l;
    }

    /**
     * 测量辅音序列的数量
     */
    private int m() {
        int n = 0;
        int i = k0;

        while (true) {
            if (i > j) return n;
            if (!cons(i)) break;
            i++;
        }
        i++;

        while (true) {
            while (true) {
                if (i > j) return n;
                if (cons(i)) break;
                i++;
            }
            i++;
            n++;
            while (true) {
                if (i > j) return n;
                if (!cons(i)) break;
                i++;
            }
            i++;
        }
    }

    /**
     * 检查字符是否为辅音（带边界检查）
     */
    private boolean cons(int i) {
        if (i < k0 || i > k) return false;

        switch (safeCharAt(i)) {
            case 'a': case 'e': case 'i': case 'o': case 'u':
                return false;
            case 'y':
                return (i == k0) ? true : !cons(i - 1);
            default:
                return true;
        }
    }

    /**
     * 检查词干中是否有元音
     */
    private boolean vowelInStem() {
        for (int i = k0; i <= k; i++) {
            if (!cons(i)) return true;
        }
        return false;
    }

    /**
     * 检查双辅音（带边界检查）
     */
    private boolean doubleConsonant(int j) {
        if (j < k0 + 1) return false;
        return safeCharAt(j) == safeCharAt(j - 1) && cons(j);
    }

    /**
     * 检查cvc模式（辅音-元音-辅音）
     */
    private boolean cvc(int i) {
        if (i < k0 + 2 || !cons(i) || cons(i - 1) || !cons(i - 2)) {
            return false;
        }
        char ch = safeCharAt(i);
        return ch != 'w' && ch != 'x' && ch != 'y';
    }

    /**
     * 替换词尾（带m()>0条件）
     */
    private void r(String s) {
        if (m() > 0) safeSetTo(s);
    }
}